home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Maclife 157
/
MACLIFE157-2001-09.ISO.7z
/
MACLIFE157-2001-09.ISO
/
Linux
/
MacOS Tools
/
BootX 1.2.2
/
Sources
/
src
/
bootx
/
BootX.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-07-23
|
52KB
|
2,066 lines
/* BootX
*
* Written by Benjamin Herrenschmidt
*
* portions of this code from InfiniteOS boot loader by <...>, portions from
* quik by Paul Mackerras.
*
* GPL....
*
* This file contains the entry point and GUI of BootX. It contains code
* for both the application and INIT version of BootX, but not for miBoot.
* It does not contains all the code involved in loading the kernel and
* preparing the boot process itself. This code is shared with miBoot and
* is now located in boot.c
*
*/
#include <Devices.h>
#include <Files.h>
#include <DriverServices.h>
#include <PEFBinaryFormat.h>
#include <ShutDown.h>
#include <Dialogs.h>
#include <Windows.h>
#include <Menus.h>
#include <LowMem.h>
#include <DiskInit.h>
#include <Processes.h>
#include <TextUtils.h>
#include <Resources.h>
#include <AppleEvents.h>
#include <AEDataModel.h>
#include <Folders.h>
#include <ToolUtils.h>
#include <SCSI.h>
#include <Gestalt.h>
#include <Packages.h>
#include <StandardFile.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "debug_text.h"
#ifndef macintosh
#define macintosh
#endif
#ifndef BOOTX_BUILD_INIT
#define BOOTX_BUILD_INIT (BOOTX_ENV == BOOTX_ENV_EXTENSION)
#endif
/* This option reverts to old bootx behaviour: the kernel is entered
directly, without turnig OFF the MMU. */
#ifndef NO_BOOTSTRAP
#define NO_BOOTSTRAP 0
#endif
#include "BootX.h"
#include "boot.h"
#include "ErrorCodes.h"
#include "MoreFiles.h"
#include "MoreFilesExtras.h"
#include "IterateDirectory.h"
#include "FullPath.h"
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define DEBUG_ERR(err,msg) display_error((err), msg, __FILE__, __LINE__)
#if BOOTX_BUILD_INIT
/* Procinfo of entry point */
ProcInfoType __procinfo = kPascalStackBased;
#endif
/* Dialog items IDs */
enum
{
/* Main dialog */
button_boot_linux = 2,
button_boot_macos = 3,
field_kernel_args = 5,
field_root_device = 6,
button_set_default = 7,
text_status_display = 9,
check_video_of_only = 11,
button_boot_mklinux = 14,
menu_kernels = 15,
button_options = 16,
has_ramdisk_item = 17,
root_label_1 = 12,
root_label_2 = 13,
ramd_label = 18,
field_ramd_size = 19,
/* Options dialog */
opt_check_use_ram_disk = 4,
opt_button_choose_ramdisk = 7,
opt_text_ramdisk_path = 6,
opt_check_set_l2cr = 3,
opt_check_force_video = 8,
opt_check_force_scsi_on = 5,
opt_button_ok = 1,
opt_button_cancel = 2
};
/* Resources */
enum
{
string_kernel_names = 128,
string_ramdisk_names = 129,
string_kernel_args = 130,
string_prefs_file_names = 131,
string_boot_delay = 132,
string_mkboot_names = 133,
string_mkboot_patch = 134,
string_kernel_folder = 135,
string_mkboot_patched = 257,
text_mkboot_fake_prefs = 128,
dialog_main = 131,
dialog_options = 132,
alert_error = 130,
menu_kernel_list = 1000,
icons_ramdisk = 258,
icons_gzipped = 260,
icons_normal_kernel = 259
};
/* Boot choice */
enum
{
boot_macos = 0,
boot_linux,
boot_mklinux,
boot_choice_count = 3
};
static short g_boot_choices[boot_choice_count][2] =
{
button_boot_macos , 1,
button_boot_linux , 0,
button_boot_mklinux , 0
};
/* Struct used for mount event queue */
typedef struct saved_mount
{
QElem link;
UInt32 message;
} saved_mount_t;
/* An item in the kernel list. Note that an empty name
means a separator item */
typedef struct kernel_item
{
boot_file_t file;
boot_kernel_desc_t kdesc;
boot_ramdisk_desc_t rdesc;
Boolean has_rd;
short menu_item;
} kernel_item_t;
#define MAX_KERNEL_ITEMS 32
/* Preferences */
#define BOOTX_PREFS_VERSION 5
#define BOOTX_PREFS_COMPATIBLE_VERSION 1
#pragma options align=power
typedef struct bootx_prefs
{
/* Version of this structure */
unsigned long version;
/* backward compatible down to version: */
unsigned long compatible_version;
unsigned char boot_choice; // uchar for compatibility
Boolean use_ramdisk;
Boolean video_of_only;
Boolean use_l2cr_settings;
Boolean force_video_setup;
Boolean force_scsi_on;
Boolean unused_boolean[2];
Str255 command_line;
Str32 root_device;
Str63 kernel_name;
char ramdisk_path[1024];
UInt32 ramdisk_size;
} bootx_prefs, **bootx_prefs_handle;
#pragma options align=reset
/* Generic tools */
inline void
pstrcpy(Str255 dst, ConstStr255Param src)
{
memcpy(dst, src, src[0] + 1);
}
inline void
pstrncpy(Str255 dst, ConstStr255Param src, unsigned long max_size)
{
unsigned char l = (src[0] > max_size) ?
max_size : src[0]; memcpy(dst, src, l+1);
dst[0] = l;
}
inline void
pstrcat(Str255 dst, ConstStr255Param append)
{
int size = append[0];
if ((dst[0] + size) > 255)
size = 255 - dst[0];
memcpy(&dst[dst[0]+1], &append[1], size);
dst[0] += size;
}
/* --- Prototypes -------------------------------------- */
typedef void (*iterate_device_proc)(RegEntryIDPtr entryID);
pascal void main(void);
static void init_macos_toolbox(void);
static Boolean create_dialog(void);
static void dispose_dialog(void);
static Boolean locate_ramdisk(void);
static void setup_default_buttons(void);
static void display_error(OSErr err, int msg, char *file, int line);
static void fill_boot_options( boot_kernel_desc_t **out_kernel_infos,
boot_ramdisk_desc_t **out_ramdisk_infos,
boot_params_t *out_params);
static OSErr locate_file(short namesResourceID, OSType defaultFolder, FSSpecPtr outSpec);
static void load_prefs(void);
static void save_prefs(void);
static void do_boot_mklinux(void);
static Boolean locate_mklinux(void);
static Boolean add_kernel_file(FSSpec *in_spec);
static void lookup_kernels(void);
static void do_main_dialog(void);
static void do_options_dialog(void);
static pascal void kernel_iterate_filter_proc( const CInfoPBRec* const cpbPtr,
Boolean *quitFlag,
void* yourDataPtr);
static void build_kernels_menu(void);
static void setup_debug_context(Boolean debug_visible);
static void check_opt_keys(void);
static void debug_checkpoint(void);
static void show_context(void);
static pascal void ramdisk_icon_item_proc(WindowPtr theWindow, DialogItemIndex itemNo);
static void kernel_selection_changed();
static Boolean choose_ramdisk_file(boot_file_t* file, boot_ramdisk_desc_t* desc);
#if BOOTX_BUILD_INIT
static void save_mount_event(EventRecord *event);
static void resend_mount_events(void);
#endif
// CFM stuffs
pascal OSErr FragmentInitialize(const CFragInitBlockPtr initInfo);
pascal void FragmentTerminate(void);
pascal OSErr __initialize(const CFragInitBlockPtr initInfo);
pascal void __terminate(void);
/* --- Globals ----------------------------------------- */
extern int device_tree_skip_macos;
extern int device_tree_max_prop_length;
dt_context* dct;
static dt_context g_dct;
static Boolean g_use_ramdisk;
static void* g_ramdisk;
static boot_ramdisk_desc_t g_std_ramdisk;
static boot_file_t g_std_ramdisk_file;
static Boolean g_video_of_only;
static ControlHandle g_video_of_only_cntl;
static DialogPtr g_dialog;
static THz g_my_zone;
static FSSpec g_mkboot_spec;
static Boolean g_have_ramdisk;
static int g_current_choice;
static UInt32 g_entry_ticks;
static UInt32 g_autoboot_delay;
static Handle g_status_item;
static QHdr g_mount_queue;
static Boolean g_vm_present;
static Boolean g_L2CR_pref;
static Boolean g_L2CR_set;
static Boolean g_L2CR_available;
static UInt32 g_L2CR_value;
/*static*/ Boolean g_arch_PCI; /* Needed by do_boot to avoid device tree copy on Nubus */
static ControlHandle g_kernel_menu = NULL;
static kernel_item_t g_kernel_items[MAX_KERNEL_ITEMS];
static UInt32 g_kernel_items_count = 0;
static Boolean g_debug_visible = 0;
static Boolean g_current_kernel_has_rd = false;
static Boolean g_force_video_setup = false;
static Boolean g_force_scsi_on = false;
static Handle ramd_size_field;
static Boolean g_reset_ata = true;
#if !BOOTX_BUILD_INIT
static FSSpec g_application_spec;
#endif
static RGBColor g_back_color = {0xEEEE, 0xEEEE, 0xEEEE};
/* --- Implementation ---------------------------------- */
/* Pre-initialize */
pascal OSErr
FragmentInitialize(const CFragInitBlockPtr /*initInfo*/)
{
// -- Not needed if we don't use C++
// OSErr err = __initialize(initInfo);
// if (err != noErr)
// return err;
//
// g_my_connection_ID = (CFragConnectionID)initInfo->connectionID;
//
//
// SetDriverClosureMemory(initInfo->closureID, true);
return noErr;
}
pascal void
FragmentTerminate(void)
{
// -- Not needed if we don't use C++
// __terminate();
// DebugStr("¥pFrag term");
}
/* Initialize MacOS managers */
void
init_macos_toolbox(void)
{
#if !BOOTX_BUILD_INIT
OSErr err;
ProcessInfoRec infos;
ProcessSerialNumber me;
Str255 my_name;
#endif
InitGraf(&qd.thePort);
InitFonts();
InitWindows();
#if BOOTX_BUILD_INIT
InitMenus();
#endif
TEInit();
InitDialogs(nil);
#if BOOTX_BUILD_INIT
InitAllPacks();
#endif
InitCursor();
#if BOOTX_BUILD_INIT
LMSetDeskHook(NULL);
LMSetDragHook(NULL);
LMSetGhostWindow(NULL);
TextFont(0);
TextSize(12);
DrawMenuBar();
#endif
#if BOOTX_BUILD_INIT
MoreMasters();
#else
MaxApplZone();
MoreMasters();
MoreMasters();
MoreMasters();
MoreMasters();
FlushEvents(everyEvent, 0);
err = GetCurrentProcess(&me);
if (err != noErr) {
DEBUG_ERR(err, error_get_current_process);
ExitToShell();
}
memset(&infos, 0, sizeof(ProcessInfoRec));
infos.processInfoLength = sizeof(ProcessInfoRec);
infos.processName = my_name;
infos.processAppSpec = &g_application_spec;
err = GetProcessInformation(&me, &infos);
if (err != noErr)
{
DEBUG_ERR(err, error_get_process_infos);
ExitToShell();
}
#endif
}
static RoutineDescriptor ramdisk_icon_item_desc =
BUILD_ROUTINE_DESCRIPTOR(uppUserItemProcInfo, ramdisk_icon_item_proc);
static pascal void ramdisk_icon_item_proc(WindowPtr theWindow, DialogItemIndex itemNo)
{
Handle hdl;
Rect rect;
DialogItemType type;
SetPort(theWindow);
GetDialogItem(theWindow, itemNo, &type, &hdl, &rect);
PlotIconID(&rect, kAlignNone, kTransformNone, icons_ramdisk);
}
/* Create the dialog, setup initial values, and gather infos about some
* of the items for later use.
*/
Boolean
create_dialog()
{
DialogPeek dp;
short itemType;
Rect itemBox;
Handle itemHandle;
FontInfo theFontInfo;
Str32 tempStr;
g_dialog = GetNewDialog(dialog_main, NULL, (WindowPtr)-1);
if (!g_dialog)
{
DEBUG_ERR(0, error_create_dialog);
return false;
}
SetPort(g_dialog);
dp = (DialogPeek)g_dialog;
TextFont((**(dp->textH)).txFont = 3);
TextSize((**(dp->textH)).txSize = 9);
TextFace((**(dp->textH)).txFace = 0);
GetFontInfo(&theFontInfo);
(**(dp->textH)).lineHeight = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading;
(**(dp->textH)).fontAscent = theFontInfo.ascent;
GetDialogItem(g_dialog, text_status_display, &itemType, &g_status_item, &itemBox) ;
GetDialogItem(g_dialog, button_boot_linux, &itemType, &itemHandle, &itemBox) ;
if (!g_boot_choices[boot_linux][1])
HiliteControl((ControlHandle)itemHandle, 255);
GetDialogItem(g_dialog, button_boot_mklinux, &itemType, &itemHandle, &itemBox) ;
#if BOOTX_BUILD_INIT
if (!g_boot_choices[boot_mklinux][1])
HiliteControl((ControlHandle)itemHandle, 255);
#else
HideDialogItem(g_dialog, button_boot_mklinux);
#endif
GetDialogItem(g_dialog, check_video_of_only, &itemType, (Handle *)&g_video_of_only_cntl, &itemBox) ;
GetDialogItem(g_dialog, has_ramdisk_item, &itemType, &itemHandle, &itemBox) ;
SetDialogItem(g_dialog, has_ramdisk_item, itemType, (Handle)&ramdisk_icon_item_desc, &itemBox) ;
HideDialogItem(g_dialog, has_ramdisk_item);
GetDialogItem(g_dialog, field_ramd_size, &itemType, &ramd_size_field, &itemBox) ;
NumToString(8192, tempStr);
SetDialogItemText(ramd_size_field, tempStr);
SetDialogTracksCursor(g_dialog, true);
RGBBackColor(&g_back_color);
GetDialogItem(g_dialog, menu_kernels, &itemType, (Handle *)&g_kernel_menu, &itemBox);
return true;
}
void
fill_boot_options( boot_kernel_desc_t **out_kernel_infos,
boot_ramdisk_desc_t **out_ramdisk_infos,
boot_params_t *out_params)
{
short itemType;
Rect itemBox;
Handle itemHandle;
static Str255 tempStr;
static Str255 args;
int i, choice;
boot_kernel_desc_t* ki;
boot_ramdisk_desc_t* ri;
tempStr[0] = args[0] = 0;
out_params->close_video = true;
out_params->no_relocation = false;
out_params->setup_video = g_force_video_setup;
out_params->force_scsi = g_force_scsi_on;
out_params->override_l2cr = g_L2CR_set;
out_params->l2cr_value = g_L2CR_value;
out_params->reset_ata = g_reset_ata;
if (!g_use_ramdisk && !g_current_kernel_has_rd) {
GetDialogItem(g_dialog, field_root_device, &itemType, &itemHandle, &itemBox);
if (itemHandle)
GetDialogItemText(itemHandle, tempStr);
if (tempStr[0]) {
pstrcpy(args, "¥proot=/dev/");
pstrcat(args, tempStr);
}
} else {
long size;
GetDialogItemText(ramd_size_field, tempStr);
StringToNum(tempStr, &size);
if (size) {
NumToString(size, tempStr);
pstrcpy(args, "¥pramdisk_size=");
pstrcat(args, tempStr);
}
}
tempStr[0] = 0;
GetDialogItem(g_dialog, field_kernel_args, &itemType, &itemHandle, &itemBox);
if (itemHandle)
GetDialogItemText(itemHandle, tempStr);
if (tempStr[0]) {
if (args[0])
pstrcat(args, "¥p ");
pstrcat(args, tempStr);
}
// Eventually update kernel args for ofonly mode
if (g_video_of_only) {
if (args[0])
pstrcat(args, "¥p ");
pstrcat(args, "¥pvideo=ofonly");
}
// Get selected kernel
choice = 0;
for (i=0; i<g_kernel_items_count; i++)
if (g_kernel_items[i].menu_item == GetControlValue(g_kernel_menu))
choice = i;
pstrcpy((StringPtr)out_params->args, args);
p2cstr((StringPtr)out_params->args);
*out_kernel_infos = ki = &g_kernel_items[choice].kdesc;
ri = NULL;
if (g_kernel_items[choice].has_rd)
ri = &g_kernel_items[choice].rdesc;
else if (g_use_ramdisk) {
ri = &g_std_ramdisk;
}
*out_ramdisk_infos = ri;
}
/* I'll let you guess what this function does ;-)
*/
void
dispose_dialog()
{
Boolean hasEvent;
/* Flush any pending update event */
do {
EventRecord event;
hasEvent = WaitNextEvent(everyEvent & (~diskMask), &event, 1, NULL);
if (hasEvent && (event.what == updateEvt)) {
SetPort((WindowPtr)event.message);
BeginUpdate((WindowPtr)event.message);
EndUpdate((WindowPtr)event.message);
}
} while(hasEvent);
/* Get rid of the dialog */
DisposeDialog(g_dialog);
g_dialog = NULL;
}
void
setup_default_buttons(void)
{
Rect r_erase, r_fill;
RgnHandle erase_rgn, rgn1, rgn2;
PenState state;
short button, i;
short itemType;
Handle itemHandle;
SetPort(g_dialog);
button = g_boot_choices[g_current_choice][0];
SetDialogDefaultItem(g_dialog, button);
SetDialogCancelItem(g_dialog, button_boot_macos);
erase_rgn = NewRgn();
rgn1 = NewRgn();
rgn2 = NewRgn();
for (i=0; i<boot_choice_count; i++)
if (i == g_current_choice)
GetDialogItem(g_dialog, g_boot_choices[i][0], &itemType, &itemHandle, &r_fill) ;
else
{
GetDialogItem(g_dialog, g_boot_choices[i][0], &itemType, &itemHandle, &r_erase);
RectRgn(rgn1, &r_erase);
InsetRect(&r_erase, -4, -4);
RectRgn(rgn2, &r_erase);
DiffRgn(rgn2, rgn1, rgn1);
UnionRgn(rgn1, erase_rgn, erase_rgn);
}
/* We still do the erasing & drawing of the default outline
since some versions of the default filter proc will not handle
correctly the dynamic changing. Appearance Manager patches
FrameRoundRect so this won't harm. Under MacOS 8.1, the Appearance
won't be available so early during boot. Under 8.5, things seems to be
different and you'll get the AM look at startup.
*/
GetPenState(&state);
PenNormal();
PenSize(3,3);
InsetRect(&r_fill, -4, -4);
EraseRgn(erase_rgn);
FrameRoundRect(&r_fill, 16, 16);
SetPenState(&state);
DisposeRgn(rgn1);
DisposeRgn(rgn2);
DisposeRgn(erase_rgn);
}
OSErr
locate_file(short namesResourceID, OSType defaultFolder, FSSpecPtr outSpec)
{
int i;
OSErr err;
short defaultVRefNum;
long defaultParID;
static Str255 fileName;
#if !BOOTX_BUILD_INIT
Boolean tryApp;
#endif
// Build kernel FSSpec
err = FindFolder( kOnSystemDisk,
defaultFolder,
false,
&defaultVRefNum,
&defaultParID);
if (err != noErr)
return err;
i=1;
#if !BOOTX_BUILD_INIT
tryApp = true;
#endif
do
{
GetIndString(fileName, namesResourceID, i);
if (fileName[0] == 0)
{
#if !BOOTX_BUILD_INIT
if (tryApp)
{
tryApp = false;
i = 1;
continue;
}
#endif
return fnfErr;
}
#if BOOTX_BUILD_INIT
err = FSMakeFSSpec( defaultVRefNum, defaultParID, fileName, outSpec);
#else
err = FSMakeFSSpec( tryApp ? g_application_spec.vRefNum : defaultVRefNum,
tryApp ? g_application_spec.parID : defaultParID,
fileName,
outSpec);
#endif
if (err == noErr)
{
Boolean wasFolder;
Boolean wasAlias;
/* Resolve it in case it was an alias - should do it silently however !*/
ResolveAliasFile( outSpec,
true,
&wasFolder,
&wasAlias);
break;
}
i++;
} while(true);
return err;
}
/* Locate the kernel and the ram disk (optional) files on disk.
* This function uses a looks for them first next to the BootX application,
* then in the system folder's root.
* For each file, all possible names are tested. The names are stored inside
* BootX resources STR#, ID 128 for kernel names, ID 129 for ramdisk names
*/
Boolean
locate_ramdisk(void)
{
OSErr err;
FSSpec spec;
// Lookup ram disk
g_have_ramdisk = false;
err = locate_file(string_ramdisk_names, kSystemFolderType, &spec);
if (err != noErr)
err = locate_file(string_ramdisk_names, kExtensionFolderType, &spec);
if (err == noErr) {
g_std_ramdisk_file.spec = spec;
g_std_ramdisk_file.rn = -1;
g_std_ramdisk_file.size = 0;
g_std_ramdisk_file.name = g_std_ramdisk_file.spec.name;
g_have_ramdisk = check_ramdisk_file( &g_std_ramdisk_file,
&g_std_ramdisk);
}
return true;
}
#if BOOTX_BUILD_INIT
/* Save bad mount events in our special queue. We repost them later so they can
* eventually be handled by an external file system that gets loaded after
* us (like MountX).
*/
void
save_mount_event(EventRecord *event)
{
saved_mount_t* stub;
static s_save_count = 0;
dt_printf(dct, "saving mount event, msg: 0x%x, error: 0x%x¥n",
(int)LoWord(event->message), HiWord(event->message));
if ((++s_save_count) > 128) {
DEBUG_ERR(-666, error_too_many_mounts);
return;
}
stub = (saved_mount_t*)NewPtr(sizeof(saved_mount_t));
if (stub == NULL)
stub = (saved_mount_t*)NewPtrSys(sizeof(saved_mount_t));
if (stub == NULL) {
DEBUG_ERR(MemError(), error_alloc_event_stub);
return;
}
stub->message = event->message;
Enqueue((QElemPtr)stub, &g_mount_queue);
}
/* Repost events gathered previously */
void
resend_mount_events(void)
{
saved_mount_t* stub;
while(NULL != (stub = (saved_mount_t *)g_mount_queue.qHead))
{
if (Dequeue((QElemPtr)stub, &g_mount_queue) == noErr) {
OSErr eventResult = HiWord(stub->message);
short driveNumber = LoWord(stub->message);
dt_printf(dct,"posting event, drive: 0x%x, error was: 0x%x¥n", (int)driveNumber, eventResult);
SetZone(SystemZone());
PostEvent(diskEvt, driveNumber);
SetZone(g_my_zone);
DisposePtr((Ptr)stub);
}
}
}
#endif
Boolean
add_kernel_file(FSSpec *in_spec)
{
UInt32 index = g_kernel_items_count;
kernel_item_t *item = &g_kernel_items[index];
if (index >= MAX_KERNEL_ITEMS)
false;
memset(item, 0, sizeof(kernel_item_t));
item->file.spec = *in_spec;
item->file.name = item->file.spec.name;
item->file.rn = -1;
item->file.size = 0;
item->kdesc.file = &item->file;
item->rdesc.file = &item->file;
item->has_rd = false;
item->menu_item = -1;
if (check_kernel_file(&item->file, &item->kdesc, &item->rdesc, &item->has_rd)) {
g_kernel_items_count++;
return true;
}
return false;
}
/* This function looks up possible linux kernel files and fills the
kernel menu */
void
lookup_kernels(void)
{
FSSpec spec, folder_spec, previous;
Str255 folder_name;
Boolean isDir, has_previous;
long folder_id, defaultParID;
short defaultVRefNum;
OSErr err;
// Lookup kernel old way in system folder/application
has_previous = false;
err = locate_file(string_kernel_names, kSystemFolderType, &spec);
if (err == noErr) {
if (add_kernel_file(&spec)) {
has_previous = true;
previous = spec;
}
}
// Lookup kernel old way in extensions folder/application
err = locate_file(string_kernel_names, kExtensionFolderType, &spec);
if (err == noErr) {
if (!(has_previous && (spec.vRefNum == previous.vRefNum)
&& (spec.parID == previous.parID)
&& EqualString(spec.name, previous.name, false, false)))
add_kernel_file(&spec);
}
GetIndString(folder_name, string_kernel_folder, 1);
// Now check for a "Linux Kernels" folder next to BootX (app only)
#if !BOOTX_BUILD_INIT
err = FSMakeFSSpec( g_application_spec.vRefNum,
g_application_spec.parID,
folder_name, &folder_spec);
if (err == noErr) {
Boolean wasFolder;
Boolean wasAlias;
/* Resolve it in case it was an alias - should do it silently however !*/
ResolveAliasFile(&folder_spec, true, &wasFolder, &wasAlias);
err = FSpGetDirectoryID(&folder_spec, &folder_id, &isDir);
if ((err == noErr) && isDir) {
err = FSpIterateDirectory( &folder_spec,
1,
kernel_iterate_filter_proc,
NULL);
}
}
#endif
// Now check for a "Linux Kernels" folder in the system folder
// Build kernel FSSpec
err = FindFolder( kOnSystemDisk,
kSystemFolderType,
false,
&defaultVRefNum,
&defaultParID);
if (err == noErr) {
err = FSMakeFSSpec( defaultVRefNum,
defaultParID,
folder_name, &folder_spec);
if (err == noErr) {
Boolean wasFolder;
Boolean wasAlias;
/* Resolve it in case it was an alias - should do it silently however !*/
ResolveAliasFile(&folder_spec, true, &wasFolder, &wasAlias);
err = FSpGetDirectoryID(&folder_spec, &folder_id, &isDir);
if ((err == noErr) && isDir) {
err = FSpIterateDirectory( &folder_spec,
1,
kernel_iterate_filter_proc,
NULL);
}
}
}
}
pascal void
kernel_iterate_filter_proc( const CInfoPBRec* const cpbPtr,
Boolean *quitFlag,
void* yourDataPtr)
{
#pragma unused (quitFlag,yourDataPtr)
FSSpec spec;
pstrcpy(spec.name, cpbPtr->hFileInfo.ioNamePtr);
spec.parID = cpbPtr->hFileInfo.ioFlParID;
spec.vRefNum = cpbPtr->hFileInfo.ioVRefNum;
add_kernel_file(&spec);
}
void
build_kernels_menu(void)
{
int item, i;
short lastVol;
long lastDirID;
MenuHandle menu;
PopupPrivateDataHandle dataH;
lastDirID = 0;
lastVol = 0;
item = 1;
dataH = (PopupPrivateDataHandle) (**g_kernel_menu).contrlData;
menu = NULL;
if (dataH != NULL)
menu = (**dataH).mHandle;
if (!menu)
return;
while(CountMenuItems(menu))
DeleteMenuItem(menu, 1);
for (i=0; i<g_kernel_items_count; i++) {
if ((item > 1) && ((g_kernel_items[i].file.spec.vRefNum != lastVol)
|| (g_kernel_items[i].file.spec.parID != lastDirID))) {
AppendMenu(menu, "¥p(-");
item++;
}
AppendMenu(menu, "¥p ");
SetMenuItemText(menu, item, g_kernel_items[i].file.name);
g_kernel_items[i].menu_item = item;
if (g_kernel_items[i].has_rd)
SetItemIcon(menu, item, icons_ramdisk);
else if (g_kernel_items[i].kdesc.zImage)
SetItemIcon(menu, item, icons_gzipped);
else
SetItemIcon(menu, item, icons_normal_kernel);
item++;
lastDirID = g_kernel_items[i].file.spec.parID;
lastVol = g_kernel_items[i].file.spec.vRefNum;
}
SetControlMinimum(g_kernel_menu, 1);
SetControlMaximum(g_kernel_menu, item);
SetControlValue(g_kernel_menu, 1);
}
/* Entry point */
pascal void
main(void)
{
GrafPtr oldPort;
long response;
static Str255 tempStr;
/* Silently dies on sheepshaver */
if (((*(UInt32 *)0x2800)) == 'Baah') {
#if BOOTX_BUILD_INIT
FragmentTerminate();
#endif
return;
}
g_my_zone = GetZone();
#if BOOTX_TRACE
#if BOOTX_BUILD_INIT
ST_TraceInit("BootX INIT", 1, NULL);
#else
ST_TraceInit("BootX App", 1, NULL);
#endif
#endif
check_opt_keys();
setup_debug_context(g_debug_visible);
show_context();
dt_printf(dct, "Initing MacOS Toolbox...¥n");
init_macos_toolbox();
dt_printf(dct, "Initing BootX...¥n");
g_dialog = NULL;
g_mount_queue.qHead = NULL;
g_mount_queue.qTail = NULL;
g_mount_queue.qFlags = NULL;
g_ramdisk = NULL;
g_L2CR_pref = false;
g_L2CR_set = false;
g_L2CR_value = 0;
g_L2CR_available = false;
g_entry_ticks = TickCount();
g_force_video_setup = true;
g_vm_present = false;
if (Gestalt(gestaltVMAttr, &response) == noErr)
if (response & (1 << gestaltVMPresent))
g_vm_present = true;
if (Gestalt(gestaltNativeCPUfamily, &response) == noErr)
{
if (response == gestaltCPU750)
g_L2CR_available = true;
} else if (Gestalt(gestaltNativeCPUtype, &response) == noErr)
if (response == gestaltCPU750)
g_L2CR_available = true;
g_arch_PCI = false;
if (Gestalt(gestaltOpenFirmwareInfo, &response) == noErr)
if (Gestalt(gestaltNameRegistryVersion, &response) == noErr)
g_arch_PCI = true;
if (((long)RegistryEntryIDInit == kUnresolvedCFragSymbolAddress)||
((long)FlushProcessorCache == kUnresolvedCFragSymbolAddress))
g_arch_PCI = false;
// g_page_size = g_arch_PCI ? GetLogicalPageSize() : 4096;
GetWMgrPort(&oldPort);
SetPort(oldPort);
// Setup default BootX options
// GetIndString(g_kernel_args, string_kernel_args, 1);
GetIndString(tempStr, string_boot_delay, 1);
StringToNum(tempStr, (long *)&g_autoboot_delay);
g_autoboot_delay *= 60;
g_current_choice = boot_macos;
g_video_of_only = false;
// Setup device tree options
device_tree_skip_macos = 1; // Skip MacOS drivers
device_tree_max_prop_length = 1024; // Max copied property length
// Locate the kernel files
dt_printf(dct, "Looking up valid kernels...¥n");
lookup_kernels();
dt_printf(dct, "Found %d kernels¥n", g_kernel_items_count);
g_boot_choices[boot_linux][1] = (g_kernel_items_count != 0);
// Locate the default (old way) ramdisk. Prefs can override this
if (g_kernel_items_count)
locate_ramdisk();
g_use_ramdisk = g_have_ramdisk;
#if BOOTX_BUILD_INIT
// Locate MkLinux booter
g_boot_choices[boot_mklinux][1] = locate_mklinux();
#endif
dt_printf(dct, "VM present : %d¥n", g_vm_present);
// dt_printf(dct, "Page size : %d¥n", g_page_size);
dt_printf(dct, "Autoboot_delay : %d¥n", g_autoboot_delay);
dt_printf(dct, "L2CR available on this CPU : %d¥n", g_L2CR_available);
dt_printf(dct, "PCI Arch : %d¥n", g_arch_PCI);
if (g_have_ramdisk)
dt_printf(dct, "default RAM-disk found¥n");
if (g_boot_choices[boot_mklinux][1])
dt_printf(dct, "MkLinux booter found¥n");
if (!g_boot_choices[boot_linux][1] && !g_boot_choices[boot_mklinux][1]) {
DEBUG_ERR(0, error_no_kernel);
goto bail;
}
// Create main dialog box
if (!create_dialog())
goto bail;
if (g_kernel_items_count)
build_kernels_menu();
// Load eventual prefs file
load_prefs();
// Display the dialog
SelectDialogItemText(g_dialog, field_kernel_args, 0, 255);
ShowWindow(g_dialog);
DrawDialog(g_dialog);
// Main event loop
do_main_dialog();
// Check user choice and boot
if (g_current_choice == boot_linux) {
boot_kernel_desc_t *kernel_infos;
boot_ramdisk_desc_t *ramdisk_infos;
boot_params_t params;
/* A little bit hacky ... */
static char args[2048];
params.args = args;
fill_boot_options(&kernel_infos, &ramdisk_infos, ¶ms);
if (kernel_infos) {
dispose_dialog();
SetZone(SystemZone());
SetCursor(*GetCursor(watchCursor));
dt_printf(dct, "Begin Linux boot...¥n");
debug_checkpoint();
do_boot(kernel_infos, ramdisk_infos, ¶ms);
#if BOOTX_BUILD_INIT
DebugStr("¥pShould not get here !");
#endif
SetZone(g_my_zone);
}
} else if (g_current_choice == boot_mklinux) {
dt_printf(dct, "Begin MkLinux boot...¥n");
SetZone(g_my_zone);
dispose_dialog();
do_boot_mklinux();
}
bail:
dt_printf(dct, "Exiting BootX !¥n");
SetZone(g_my_zone);
if (g_dialog)
dispose_dialog();
GetWMgrPort(&oldPort);
SetPort(oldPort);
#if BOOTX_BUILD_INIT
resend_mount_events();
#endif
#if BOOTX_BUILD_INIT
FragmentTerminate();
#endif
}
void
do_main_dialog(void)
{
Boolean finished;
Boolean counter_on;
Boolean stop_counter;
Boolean simulate;
ModalFilterUPP std_filter;
UInt32 last_disp_ticks;
DialogPtr dialog;
finished = false;
simulate = false;
stop_counter = false;
#if BOOTX_BUILD_INIT
counter_on = true;
#else
counter_on = false;
#endif
last_disp_ticks = g_entry_ticks - 60;
if (GetStdFilterProc(&std_filter) != noErr) {
std_filter = NULL;
}
kernel_selection_changed();
while(!finished) {
EventRecord event;
short itemHit;
Boolean handled;
Boolean hasEvent;
short curField;
SetPort(g_dialog);
hasEvent = WaitNextEvent(everyEvent, &event, 1, NULL);
SetPort(g_dialog);
SetZone(g_my_zone);
itemHit = 0;
handled = false;
if (counter_on) {
UInt32 now = TickCount();
if ((now - g_entry_ticks) >= g_autoboot_delay) {
counter_on = false;
itemHit = g_boot_choices[g_current_choice][0];
simulate = true;
handled = true;
}
else if ((now - last_disp_ticks) >= 30) {
static char temp[256];
sprintf(temp, "Boot in %d seconds ", (int)((g_autoboot_delay - (now - g_entry_ticks)) / 60));
c2pstr(temp);
SetDialogItemText(g_status_item, (StringPtr)temp);
last_disp_ticks = now;
}
}
if (!handled)
handled = ((std_filter != NULL)
? CallModalFilterProc(std_filter, g_dialog, &event, &itemHit)
: false);
curField = ((DialogPeek)g_dialog)->editField+1;
if (!handled && hasEvent) {
UInt8 c;
switch(event.what) {
case updateEvt:
if ((DialogPtr)event.message == g_dialog) {
handled = TRUE;
BeginUpdate(g_dialog);
RGBBackColor(&g_back_color);
DrawDialog(g_dialog);
setup_default_buttons();
EndUpdate(g_dialog);
} else {
BeginUpdate((WindowPtr)event.message);
EndUpdate((WindowPtr)event.message);
}
break;
case keyDown:
case autoKey:
c = (event.message & charCodeMask);
if (event.modifiers & cmdKey) {
switch(c) {
case 'q':
case 'Q':
itemHit = button_boot_macos;
handled = true;
break;
case 's':
case 'S':
itemHit = button_set_default;
handled = true;
simulate = true;
break;
case 'o':
case 'O':
itemHit = button_options;
handled = true;
simulate = true;
break;
}
} else {
switch(c) {
case 0x09: // Tab
do
g_current_choice = (g_current_choice + 1) % boot_choice_count;
while(!g_boot_choices[g_current_choice][1]);
setup_default_buttons();
handled = true;
break;
}
if (!handled && (curField == field_ramd_size)) {
if ((c < '0') || (c > '9')) {
// dt_printf(dct, "key: 0x%x¥n", c);
switch(c) {
case 8:
case 0x1c:
case 0x1d:
case 0x1e:
case 0x1f:
case 0x7f:
break;
default:
event.what = nullEvent;
}
}
}
}
// We stop the counter when a key is pressed
stop_counter = true;
break;
case diskEvt:
dt_printf(dct, "Got mount event, msg: 0x%08lx¥n", event.message);
#if BOOTX_BUILD_INIT
save_mount_event(&event);
#else
if ((HiWord(event.message) != noErr)&&(HiWord(event.message) != volOnLinErr)) {
Point pt = {100, 100};
DIBadMount(pt, event.message);
}
#endif
break;
}
}
// All non-filtered events are given to the default event proc.
dialog = g_dialog;
if (!handled && IsDialogEvent(&event)) {
handled = DialogSelect(&event, &dialog, &itemHit);
}
if (handled) {
if (dialog == g_dialog) {
int i;
if (simulate) {
Rect itemBox;
short itemType;
Handle itemHandle;
UInt32 toto;
GetDialogItem (g_dialog, itemHit, &itemType, &itemHandle, &itemBox);
HiliteControl((ControlHandle)itemHandle, 1);
Delay(10, &toto);
HiliteControl((ControlHandle)itemHandle, 0);
simulate = false;
}
for(i=0; i<boot_choice_count; i++)
if (g_boot_choices[i][0] == itemHit) {
g_current_choice = i;
finished = true;
break;
}
switch(itemHit)
{
case button_set_default:
stop_counter = true;
save_prefs();
break;
case check_video_of_only:
stop_counter = true;
g_video_of_only = !g_video_of_only;
SetControlValue(g_video_of_only_cntl, g_video_of_only);
break;
case menu_kernels:
stop_counter = true;
kernel_selection_changed();
break;
case button_options:
do_options_dialog();
kernel_selection_changed();
break;
}
}
}
if (counter_on && stop_counter) {
counter_on = FALSE;
SetDialogItemText(g_status_item, "¥p");
}
if (g_use_ramdisk || g_current_kernel_has_rd) {
ShowDialogItem(g_dialog, has_ramdisk_item);
ShowDialogItem(g_dialog, ramd_label);
ShowDialogItem(g_dialog, field_ramd_size);
HideDialogItem(g_dialog, field_root_device);
HideDialogItem(g_dialog, root_label_1);
HideDialogItem(g_dialog, root_label_2);
} else {
HideDialogItem(g_dialog, has_ramdisk_item);
HideDialogItem(g_dialog, ramd_label);
HideDialogItem(g_dialog, field_ramd_size);
ShowDialogItem(g_dialog, field_root_device);
ShowDialogItem(g_dialog, root_label_1);
ShowDialogItem(g_dialog, root_label_2);
}
}
}
Boolean
choose_ramdisk_file(boot_file_t* file, boot_ramdisk_desc_t* desc)
{
StandardFileReply reply;
StandardGetFile(NULL, 0, NULL, &reply);
if (!reply.sfGood)
return false;
file->spec = reply.sfFile;
return check_ramdisk_file(file, desc);
}
void
do_options_dialog(void)
{
Boolean finished;
ModalFilterUPP std_filter;
DialogPtr dialog, dlg;
ControlHandle use_ramdisk_cntl;
ControlHandle set_L2CR_cntl;
ControlHandle choose_rd_cntl;
ControlHandle force_video_cntl;
ControlHandle force_scsi_cntl;
Handle rd_path_item;
DialogPeek dp;
short itemType;
Rect itemBox;
// Handle itemHandle;
FontInfo theFontInfo;
Boolean has_rd_defined;
Boolean use_rd;
static boot_file_t ramdisk_file;
static boot_file_t ramdisk_temp;
static boot_ramdisk_desc_t ramdisk_desc;
static Str255 tempStr;
dialog = GetNewDialog(dialog_options, NULL, (WindowPtr)-1);
if (!dialog) {
DEBUG_ERR(0, error_create_dialog);
return;
}
SetPort(dialog);
dp = (DialogPeek)dialog;
TextFont((**(dp->textH)).txFont = 3);
TextSize((**(dp->textH)).txSize = 9);
TextFace((**(dp->textH)).txFace = 0);
GetFontInfo(&theFontInfo);
(**(dp->textH)).lineHeight = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading;
(**(dp->textH)).fontAscent = theFontInfo.ascent;
GetDialogItem(dialog, opt_check_use_ram_disk, &itemType, (Handle *)&use_ramdisk_cntl, &itemBox) ;
GetDialogItem(dialog, opt_check_set_l2cr, &itemType, (Handle *)&set_L2CR_cntl, &itemBox);
GetDialogItem(dialog, opt_button_choose_ramdisk, &itemType, (Handle *)&choose_rd_cntl, &itemBox);
GetDialogItem(dialog, opt_text_ramdisk_path, &itemType, &rd_path_item, &itemBox);
GetDialogItem(dialog, opt_check_force_video, &itemType, (Handle *)&force_video_cntl, &itemBox);
GetDialogItem(dialog, opt_check_force_scsi_on, &itemType, (Handle *)&force_scsi_cntl, &itemBox);
if (g_L2CR_available && g_L2CR_pref)
SetControlValue(set_L2CR_cntl, g_L2CR_set);
else
HiliteControl(set_L2CR_cntl, 255);
if (g_have_ramdisk) {
short pathLen;
Handle pathHandle;
has_rd_defined = true;
use_rd = g_use_ramdisk;
memcpy(&ramdisk_file, &g_std_ramdisk_file, sizeof(ramdisk_file));
memcpy(&ramdisk_desc, &g_std_ramdisk, sizeof(ramdisk_desc));
ramdisk_desc.file = &ramdisk_file;
SetControlValue(use_ramdisk_cntl, use_rd);
if (FSpGetFullPath(&ramdisk_file.spec, &pathLen, &pathHandle) == noErr) {
if (pathLen > 255)
pathLen = 255;
BlockMoveData(*pathHandle, tempStr+1, pathLen);
tempStr[0] = pathLen;
SetDialogItemText(rd_path_item, tempStr);
DisposeHandle(pathHandle);
}
} else {
has_rd_defined = false;
use_rd = false;
}
SetControlValue(force_video_cntl, g_force_video_setup);
SetControlValue(force_scsi_cntl, g_force_scsi_on);
SetControlValue(use_ramdisk_cntl, use_rd);
HiliteControl(choose_rd_cntl, use_rd ? 0 : 255);
SetDialogDefaultItem(dialog, opt_button_ok);
SetDialogCancelItem(dialog, opt_button_cancel);
ShowWindow(dialog);
DrawDialog(dialog);
finished = false;
if (GetStdFilterProc(&std_filter) != noErr) {
std_filter = NULL;
}
while(!finished) {
EventRecord event;
short itemHit;
Boolean handled;
Boolean hasEvent;
SetPort(dialog);
hasEvent = WaitNextEvent(everyEvent, &event, 1, NULL);
SetPort(dialog);
SetZone(g_my_zone);
itemHit = 0;
handled = false;
handled = ((std_filter != NULL)
? CallModalFilterProc(std_filter, dialog, &event, &itemHit)
: false);
if (!handled && hasEvent) {
switch(event.what) {
case updateEvt:
if ((DialogPtr)event.message == dialog) {
handled = TRUE;
BeginUpdate(dialog);
RGBBackColor(&g_back_color);
DrawDialog(dialog);
EndUpdate(dialog);
} else if ((DialogPtr)event.message == g_dialog) {
handled = TRUE;
SetPort(g_dialog);
BeginUpdate(g_dialog);
RGBBackColor(&g_back_color);
DrawDialog(g_dialog);
EndUpdate(g_dialog);
SetPort(dialog);
} else {
BeginUpdate((WindowPtr)event.message);
EndUpdate((WindowPtr)event.message);
}
break;
case diskEvt:
dt_printf(dct, "Got mount event, msg: 0x%08lx¥n", event.message);
#if BOOTX_BUILD_INIT
save_mount_event(&event);
#else
if ((HiWord(event.message) != noErr)&&(HiWord(event.message) != volOnLinErr)) {
Point pt = {100, 100};
DIBadMount(pt, event.message);
}
#endif
break;
}
}
// All non-filtered events are given to the default event proc.
dlg = dialog;
if (!handled && IsDialogEvent(&event)) {
handled = DialogSelect(&event, &dlg, &itemHit);
}
if (handled) {
if (dlg == dialog) {
switch(itemHit) {
case opt_check_use_ram_disk:
use_rd = !GetControlValue(use_ramdisk_cntl);
SetControlValue(use_ramdisk_cntl, use_rd);
HiliteControl(choose_rd_cntl, use_rd ? 0 : 255);
if (has_rd_defined)
break;
case opt_button_choose_ramdisk:
memcpy(&ramdisk_temp, &ramdisk_file, sizeof(ramdisk_temp));
if (choose_ramdisk_file(&ramdisk_temp, &ramdisk_desc)) {
short pathLen;
Handle pathHandle;
memcpy(&ramdisk_file, &ramdisk_temp, sizeof(ramdisk_file));
if (FSpGetFullPath(&ramdisk_file.spec, &pathLen, &pathHandle) == noErr) {
if (pathLen > 255)
pathLen = 255;
BlockMoveData(*pathHandle, tempStr+1, pathLen);
tempStr[0] = pathLen;
SetDialogItemText(rd_path_item, tempStr);
DisposeHandle(pathHandle);
has_rd_defined = true;
}
}
if (!has_rd_defined) {
SetControlValue(use_ramdisk_cntl, use_rd = false);
HiliteControl(choose_rd_cntl, 255);
}
break;
case opt_check_set_l2cr:
if (g_L2CR_available && g_L2CR_pref)
SetControlValue(set_L2CR_cntl, !GetControlValue(set_L2CR_cntl));
break;
case opt_check_force_video:
SetControlValue(force_video_cntl, !GetControlValue(force_video_cntl));
break;
case opt_check_force_scsi_on:
SetControlValue(force_scsi_cntl, !GetControlValue(force_scsi_cntl));
break;
case opt_button_ok:
g_use_ramdisk = use_rd;
g_have_ramdisk = has_rd_defined;
memcpy(&g_std_ramdisk_file, &ramdisk_file, sizeof(ramdisk_file));
memcpy(&g_std_ramdisk, &ramdisk_desc, sizeof(ramdisk_desc));
g_L2CR_set = GetControlValue(set_L2CR_cntl);
g_force_video_setup = GetControlValue(force_video_cntl);
g_force_scsi_on = GetControlValue(force_scsi_cntl);
finished = true;
break;
case opt_button_cancel:
finished = true;
break;
}
}
}
}
DisposeDialog(dialog);
SetPort(g_dialog);
}
void
kernel_selection_changed()
{
UInt32 choice;
UInt32 i;
// Get selected kernel
choice = 0;
g_current_kernel_has_rd = false;
for (i=0; i<g_kernel_items_count; i++) {
if (g_kernel_items[i].menu_item == GetControlValue(g_kernel_menu)) {
choice = i;
g_current_kernel_has_rd = g_kernel_items[i].has_rd;
return;
}
}
}
void
display_error(OSErr err, int msg, char *file, int line)
{
static Str32 errStr;
static Str32 lineStr;
static Str255 fileStr;
static Str255 msgStr;
strcpy((char *)fileStr, file);
c2pstr((char *)fileStr);
GetIndString(msgStr, string_error_codes, msg);
NumToString(err, errStr);
NumToString(line, lineStr);
ParamText(msgStr, errStr, fileStr, lineStr);
Alert(alert_error, NULL);
}
void
load_prefs(void)
{
FSSpec prefFileSpec;
short prefFileRef;
short saveResFile;
bootx_prefs_handle prefs;
OSErr err;
short itemType;
Rect itemBox;
Handle itemHandle;
Handle rsrc;
err = locate_file(string_prefs_file_names, kPreferencesFolderType, &prefFileSpec);
if (err != noErr)
return;
saveResFile = CurResFile();
prefFileRef = FSpOpenResFile(&prefFileSpec, fsRdPerm);
if (prefFileRef == -1)
return;
UseResFile(prefFileRef);
rsrc = Get1Resource('L2CR', 0);
if (rsrc) {
if (GetHandleSize(rsrc) == 4) {
g_L2CR_pref = true;
g_L2CR_value = *((UInt32 *)(*rsrc));
}
ReleaseResource(rsrc);
}
prefs = (bootx_prefs_handle)Get1Resource('PREF', 128);
if (prefs == NULL)
goto bail_close;
// Compare oldest compatible of prefs with version compiled with this code
if ((**prefs).compatible_version > BOOTX_PREFS_VERSION)
goto bail_release;
HLock((Handle)prefs);
g_current_choice = (**prefs).boot_choice;
g_use_ramdisk = (**prefs).use_ramdisk;
g_video_of_only = (**prefs).video_of_only;
g_L2CR_set = (**prefs).use_l2cr_settings && g_L2CR_pref;
if (!g_boot_choices[g_current_choice][1])
g_current_choice = boot_macos;
GetDialogItem(g_dialog, field_kernel_args, &itemType, &itemHandle, &itemBox);
if (itemHandle)
SetDialogItemText(itemHandle, (**prefs).command_line);
if ((**prefs).version >= 2) {
GetDialogItem(g_dialog, field_root_device, &itemType, &itemHandle, &itemBox);
if (itemHandle)
SetDialogItemText(itemHandle, (**prefs).root_device);
}
if ((**prefs).version >= 4) {
int i;
for (i=0;i<g_kernel_items_count; i++)
if (EqualString(g_kernel_items[i].file.name, (**prefs).kernel_name, false, false)) {
SetControlValue(g_kernel_menu, g_kernel_items[i].menu_item);
}
}
if ((**prefs).version >= 5) {
Str32 tempStr;
g_force_video_setup = (**prefs).force_video_setup;
g_force_scsi_on = (**prefs).force_scsi_on;
if ((**prefs).ramdisk_path[0] != 0) {
OSErr err;
FSSpec spec;
err = FSpLocationFromFullPath(
strlen((**prefs).ramdisk_path),
(**prefs).ramdisk_path,
&spec);
if (err == noErr) {
g_std_ramdisk_file.spec = spec;
g_std_ramdisk_file.rn = -1;
g_std_ramdisk_file.size = 0;
g_std_ramdisk_file.name = g_std_ramdisk_file.spec.name;
g_have_ramdisk = check_ramdisk_file( &g_std_ramdisk_file,
&g_std_ramdisk);
}
}
NumToString(8192, tempStr);
SetDialogItemText(ramd_size_field, tempStr);
}
SetControlValue(g_video_of_only_cntl, g_video_of_only);
setup_default_buttons();
bail_release:
HUnlock((Handle)prefs);
ReleaseResource((Handle)prefs);
bail_close:
CloseResFile(prefFileRef);
UseResFile(saveResFile);
}
void
save_prefs(void)
{
short prefsVRefNum;
long prefsParID;
static Str255 fileName;
FSSpec prefFileSpec;
short prefFileRef;
short saveResFile;
bootx_prefs_handle prefs;
OSErr err;
short itemType;
Rect itemBox;
Handle itemHandle;
int i;
Str32 tempStr;
UInt32 tempLong;
// Build kernel FSSpec
err = FindFolder( kOnSystemDisk,
kPreferencesFolderType,
true,
&prefsVRefNum,
&prefsParID);
if (err != noErr) {
DEBUG_ERR(err, error_access_prefs);
return;
}
GetIndString(fileName, string_prefs_file_names, 1);
saveResFile = CurResFile();
err = FSMakeFSSpec( prefsVRefNum, prefsParID, fileName, &prefFileSpec);
if (err == fnfErr) {
FSpCreateResFile(&prefFileSpec, 'BooX', 'pref', smSystemScript);
err = ResError();
}
if (err != noErr) {
DEBUG_ERR(err, error_loadcreate_prefs);
return;
}
prefFileRef = FSpOpenResFile(&prefFileSpec, fsWrPerm);
if (prefFileRef == -1) {
err = ResError();
DEBUG_ERR(err, error_openwrite_prefs);
return;
}
prefs = (bootx_prefs_handle)Get1Resource('PREF', 128);
if (prefs == NULL) {
prefs = (bootx_prefs_handle)NewHandle(sizeof(bootx_prefs));
if (prefs == NULL) {
err = MemError();
DEBUG_ERR(err, error_alloc_prefs);
goto bail_close;
}
AddResource((Handle)prefs, 'PREF', 128, "¥p");
err = ResError();
if (err != noErr)
if (prefs == NULL)
{
DisposeHandle((Handle)prefs);
DEBUG_ERR(err, error_add_prefs);
goto bail_close;
}
} else
SetHandleSize((Handle)prefs, sizeof(bootx_prefs));
HLock((Handle)prefs);
memset(*prefs, 0, sizeof(bootx_prefs));
(**prefs).version = BOOTX_PREFS_VERSION;
(**prefs).compatible_version = BOOTX_PREFS_COMPATIBLE_VERSION;
(**prefs).boot_choice = g_current_choice;
(**prefs).use_ramdisk = g_use_ramdisk;
(**prefs).video_of_only = g_video_of_only;
(**prefs).use_l2cr_settings = g_L2CR_set;
(**prefs).ramdisk_path[0] = 0;
(**prefs).force_video_setup = g_force_video_setup;
(**prefs).force_scsi_on = g_force_scsi_on;
GetDialogItem(g_dialog, field_kernel_args, &itemType, &itemHandle, &itemBox);
if (itemHandle)
GetDialogItemText(itemHandle, (**prefs).command_line);
GetDialogItem(g_dialog, field_root_device, &itemType, &itemHandle, &itemBox);
if (itemHandle)
GetDialogItemText(itemHandle, (**prefs).root_device);
for (i=0; i<g_kernel_items_count; i++)
if (g_kernel_items[i].menu_item == GetControlValue(g_kernel_menu))
pstrcpy((**prefs).kernel_name, g_kernel_items[i].file.name);
if (g_have_ramdisk) {
short pathLen;
Handle pathHandle;
err = FSpGetFullPath(&g_std_ramdisk_file.spec, &pathLen, &pathHandle);
if (err == noErr && pathHandle) {
if (pathLen > 1023)
pathLen = 1023;
BlockMoveData(*pathHandle, (**prefs).ramdisk_path, pathLen);
(**prefs).ramdisk_path[pathLen] = 0;
DisposeHandle(pathHandle);
}
}
GetDialogItemText(ramd_size_field, tempStr);
StringToNum(tempStr, (long *)&tempLong);
(**prefs).ramdisk_size = tempLong;
HUnlock((Handle)prefs);
ChangedResource((Handle)prefs);
WriteResource((Handle)prefs);
ReleaseResource((Handle)prefs);
bail_close:
CloseResFile(prefFileRef);
UseResFile(saveResFile);
FlushVol(NULL, prefsVRefNum);
}
void
do_boot_mklinux(void)
{
Handle rsrc, patch;
Str255 fileName;
OSErr err;
FSSpec prefFileSpec;
short prefFileRef, booterFileRef;
short prefsVRefNum;
long prefsParID;
long count;
// Build fake MkLinux prefs file
rsrc = Get1Resource('TEXT', text_mkboot_fake_prefs);
if (rsrc == NULL)
{
DEBUG_ERR(ResError(), error_load_mk_text);
return;
}
HNoPurge(rsrc);
patch = Get1Resource('STR#', string_mkboot_patch);
if (patch == NULL)
{
DEBUG_ERR(ResError(), error_load_mk_str);
return;
}
HNoPurge(patch);
DetachResource(patch);
err = FindFolder( kOnSystemDisk,
kPreferencesFolderType,
true,
&prefsVRefNum,
&prefsParID);
if (err != noErr)
{
DEBUG_ERR(err, error_locate_mk_prefs);
return;
}
GetIndString(fileName, string_mkboot_patch, 1);
err = FSMakeFSSpec(prefsVRefNum, prefsParID, fileName, &prefFileSpec);
if (err == fnfErr)
err = FSpCreate(&prefFileSpec, 'ttxt', 'TEXT', smSystemScript);
if (err != noErr)
{
DEBUG_ERR(err, error_open_mk_prefs);
return;
}
err = FSpOpenDF(&prefFileSpec, fsWrPerm, &prefFileRef);
if (err != noErr)
{
DEBUG_ERR(err, error_open_mk_prefs);
return;
}
err = SetEOF(prefFileRef, count = GetHandleSize(rsrc));
if (err != noErr)
{
DEBUG_ERR(err, error_write_mk_prefs);
return;
}
HLock(rsrc);
FSWrite(prefFileRef, &count, *rsrc);
FSClose(prefFileRef);
ReleaseResource(rsrc);
// Open the booter
booterFileRef = FSpOpenResFile(&g_mkboot_spec, fsRdPerm);
if (booterFileRef == -1)
{
DEBUG_ERR(ResError(), error_open_mk_booter);
return;
}
rsrc = Get1Resource('STR#', string_mkboot_patched);
if (rsrc == NULL)
{
DEBUG_ERR(ResError(), error_bad_mk_booter);
return;
}
HNoPurge(rsrc);
SetHandleSize(rsrc, GetHandleSize(patch));
BlockMoveData(*patch, *rsrc, GetHandleSize(patch));
rsrc = Get1Resource('INIT', 0);
HNoPurge(rsrc);
HLock(rsrc);
UseResFile(booterFileRef);
CallUniversalProc((UniversalProcPtr)*rsrc, kPascalStackBased);
}
Boolean
locate_mklinux(void)
{
OSErr err;
// Lookup booter
err = locate_file(string_mkboot_names, kSystemFolderType, &g_mkboot_spec);
if (err == noErr)
return true;
err = locate_file(string_mkboot_names, kExtensionFolderType, &g_mkboot_spec);
if (err == noErr)
return true;
return false;
}
static check_one_key(KeyMap map, UInt8 key_code)
{
return ((((UInt8 *)map)[key_code >> 3] >> (key_code & 7)) & 1);
}
void
check_opt_keys(void)
{
KeyMap keys;
GetKeys(keys);
if (check_one_key(keys, 0x3a))
g_debug_visible = 1;
}
void
debug_checkpoint(void)
{
KeyMap keys;
do {
GetKeys(keys);
if (!check_one_key(keys, 0x3a))
break;
} while(true);
}
void
show_context(void)
{
dt_printf(dct, "SystemZone start : 0x%08lx¥n", LMGetSysZone()->bkLim);
dt_printf(dct, "SystemZone free : 0x%08lx¥n", LMGetSysZone()->zcbFree);
dt_printf(dct, "CurrenZone start : 0x%08lx¥n", LMGetTheZone()->bkLim);
dt_printf(dct, "CurrenZone free : 0x%08lx¥n", LMGetTheZone()->zcbFree);
dt_printf(dct, "ApplZone start : 0x%08lx¥n", LMGetApplZone()->bkLim);
dt_printf(dct, "ApplZone free : 0x%08lx¥n", LMGetApplZone()->zcbFree);
dt_printf(dct, "ApplLimit : 0x%08lx¥n", LMGetApplLimit());
dt_printf(dct, "CurStackBase : 0x%08lx¥n", LMGetCurStackBase());
dt_printf(dct, "BufPtr : 0x%08lx¥n", LMGetBufPtr());
dt_printf(dct, "MemTop : 0x%08lx¥n", LMGetMemTop());
dt_printf(dct, "-> limit : 0x%08lx¥n", ((UInt32)LMGetMemTop()/2 + 1024));
}
void
setup_debug_context(Boolean debug_visible)
{
GDHandle hdl;
PixMapPtr pm;
dct = &g_dct;
memset(dct, 0, sizeof(*dct));
hdl = LMGetMainDevice();
if (hdl == NULL || (**hdl).gdPMap == NULL)
return;
pm = *(**hdl).gdPMap;
if (pm->baseAddr == NULL)
return;
dct->base = (unsigned char *)pm->baseAddr;
dct->row_bytes = pm->rowBytes & 0x3fff;
dct->width = pm->bounds.right - pm->bounds.left;
dct->height = pm->bounds.bottom - pm->bounds.top;
dct->depth = pm->pixelSize;
dct->visible = debug_visible;
if (dct->depth == 15)
dct->depth = 16;
dct->base += pm->bounds.top * dct->row_bytes;
dct->base += pm->bounds.left * (dct->depth >> 3);
dt_init(dct);
}